package com.sq.partner.manager.controller;

import java.io.BufferedReader;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.sq.partner.manager.common.Config;
import com.sq.partner.manager.common.Constants;
import com.sq.partner.manager.common.GatewayCache;
import com.sq.partner.manager.common.Result;
import com.sq.partner.manager.common.exception.AppException;
import com.sq.partner.manager.dao.CardInfoDao;
import com.sq.partner.manager.dao.FacadeNewPaymentDao;
import com.sq.partner.manager.dao.FacadePaymentDao;
import com.sq.partner.manager.mybatis.model.ActirationCardActivated;
import com.sq.partner.manager.mybatis.model.CardInfo;
import com.sq.partner.manager.mybatis.model.FacadeAppForm;
import com.sq.partner.manager.mybatis.model.FacadeNewPayment;
import com.sq.partner.manager.mybatis.model.FacadePayment;
import com.sq.partner.manager.mybatis.model.FacadeTempPolicy;
import com.sq.partner.manager.mybatis.model.GatewayUser;
import com.sq.partner.manager.service.ActirationCardActivatedService;
import com.sq.partner.manager.service.FacadeAppFormService;
import com.sq.partner.manager.service.FacadeTempPolicyService;
import com.sq.partner.manager.service.PayService;
import com.sq.partner.manager.util.DateUtil;
import com.sq.partner.manager.util.EncryptUtil;
import com.sq.partner.manager.util.FreeMarkerUtil;
import com.sq.partner.manager.util.LogUtil;
import com.sq.partner.manager.util.MD5Util;
import com.sq.partner.manager.util.StrUtil;

/**
 * 激活卡激活支付处理
 * 
 * SQ
 *
 */
@Controller
@RequestMapping("/pay")
public class ActirationCardPayController {
    private static Logger logger = LogUtil
            .getLog(ActirationCardPayController.class);

    @Resource
    private PayService payService;

    @Resource
    private FacadeTempPolicyService facadeTempPolicyService;

    @Resource
    private FacadeAppFormService facadeAppFormService;

    @Resource
    private FacadePaymentDao facadePaymentDao;

    @Resource
    private CardInfoDao cardInfoDao;

    @Resource
    private ActirationCardActivatedService activatedService;
    
    @Resource
    private FacadeNewPaymentDao facadeNewPaymentDao;

    /**
     * 跳转至新人险 个单 投保结果页面
     * 
     * @param model
     * @param stagNo
     * @param pricelessType
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/resultNlife")
    public String resultNlife(ModelMap model, String pricelessType,
            String type, HttpSession session) throws Exception {
        String urlString = "";
        ActirationCardActivated prodInfo = (ActirationCardActivated) session
                .getAttribute("prodInfo");
        if ("1".equals(type)) {
            urlString = "actirationCard/activatedCard/single/result";
            model.put("cardNo", prodInfo.getCardInfo().getCardNo());
        } else if ("2".equals(type)) {
            urlString = "actirationCard/activatedCard/group/result";
            model.put("cardNo", prodInfo.getCardInfo().getCardNo());
        } else if ("3".equals(type)) {
            urlString = "actirationCard/activatedCard/batch/result";
        }
        String stagNo = (String) session.getAttribute("stagNoJm");
        // 解密
        stagNo = EncryptUtil.decrypt(stagNo);
        FacadeTempPolicy facadeTempPolicy = payService
                .findPayFacadeTempPolicy(stagNo);

        model.put("stagNo", stagNo);
        model.put("stag_No", EncryptUtil.encrypt(stagNo));
        model.put("facadeTempPolicy", facadeTempPolicy);
        model.put("pricelessType", pricelessType);
        return urlString;
    }

    /**
     * 根据投保单号再次发起缴费确认
     * 
     * @param appNo
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/paymentConfirmAgain")
    @ResponseBody
    public Result paymentConfirmAgain(String appNo, String stagNo,
            HttpSession session, String flag) throws Exception {
        ActirationCardActivated prodInfo = (ActirationCardActivated) session
                .getAttribute("prodInfo");
        // 解密
        appNo = EncryptUtil.decrypt(appNo);
        stagNo = EncryptUtil.decrypt(stagNo);
        CardInfo cardInfo = null;

        Result result = null;
        if ("3".equals(flag)) {
            cardInfo = cardInfoDao.getCardInfoByAppNo(appNo, stagNo);
        } else {
            cardInfo = prodInfo.getCardInfo();
        }
        if ("0".equals(prodInfo.getPricelessType())) {
            // 有价激活卡缴费确认
            result = activatedService.updatePayCostCallBack(cardInfo.getCardNo(),
                    cardInfo.getCommamtId(),
                    cardInfo.getStagNo(),
                    cardInfo.getTotPremamt());
        } else {
            result = payService.newPaymentConfirmAgain(cardInfo.getCardNo(), appNo, stagNo);
        }

        return result;
    }

    /**
     * 支付接口
     * 
     * @param stagNo
     *            暂存单号
     * @return
     */
    @RequestMapping(value = "/newpayment")
    public String newpayment(HttpSession session, ModelMap model,
            String stagNo, String type) throws AppException, Exception {
        // 解密
        String decryptStagNo = EncryptUtil.decrypt(stagNo);
        // 用户信息
        GatewayUser gatewayuser = (GatewayUser) session
                .getAttribute(Constants.SESSION_USER);
        // 获取合作验证码
        String verificationCode = GatewayCache
                .getCache(Constants.FACADE_PAYMENT_KEY);
        if (StrUtil.isEmpty(verificationCode)) {
            throw new AppException("合作验证码不能为空");
        }

        FacadeTempPolicy tp = new FacadeTempPolicy();
        tp.setStagNo(decryptStagNo);
        tp = facadeTempPolicyService.findFacadeTempPolicy(tp);
        if (tp == null) {
            throw new AppException("暂存单号[" + decryptStagNo + "]无记录");
        }

        FacadePayment facadepayment = facadePaymentDao
                .queryFacadePaymentByPayidTheLatestInsertTime(decryptStagNo);
        FacadePayment payment = new FacadePayment();
        String status = "";
        if (facadepayment == null) { // 无支付记录
            payment = payService.noPaymentRecord(tp, gatewayuser.getUserCode());
        } else {
            status = facadepayment.getStatus();
            if (Constants.PAYMENT_STATUS_1.equals(status)) {
                payment = payService.noPaymentStatus(facadepayment);// 支付表是未支付状态
                if (Constants.PAYMENT_STATUS_2.equals(payment.getStatus())) {// 如果查询到已经支付成功了则直接跳转到支付成功页面
//                    }
                    List<FacadeAppForm> facadeappforms = payService
                            .alreadyPaymentStatus(decryptStagNo);

                    boolean flag = false;// 定义一个标志
                    for (FacadeAppForm facadeappform : facadeappforms) {// 循环判断是否有未生成的保单
                        if (StrUtil.isEmpty(facadeappform.getPolNo())) {
                            flag = true;
                            break;
                        }
                    }
                    if (flag) {// 如果有没生成的保单则调用缴费确认接口生成保单
                        payService.updatePayCostCallBack(facadepayment);// 调用缴费确认
                    }
                    return "/actirationCard/activatedCard/pay/success";
                }
            } else if (Constants.PAYMENT_STATUS_2.equals(status)) {// 支付表是已支付状态
                List<FacadeAppForm> facadeappforms = payService
                        .alreadyPaymentStatus(decryptStagNo);

                boolean flag = false;// 定义一个标志
                for (FacadeAppForm facadeappform : facadeappforms) {// 循环判断是否有未生成的保单
                    if (StrUtil.isEmpty(facadeappform.getPolNo())) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {// 如果有没生成的保单则调用缴费确认接口生成保单
                    payService.updatePayCostCallBack(facadepayment);// 调用缴费确认
                }

                // 跳转到对应的支付成功页面
//                if (Constants.PROD_TYPE_NLIFE.equals(tp.getProdType())) {
//                    return "forward:/pay/resultNlife?pricelessType="
//                            + prodInfo.getPricelessType()
//                            + "&type" + type;
//                }
                return "/actirationCard/activatedCard/pay/success";
                
            } else if (Constants.PAYMENT_STATUS_3.equals(status)) {// 支付表是支付失败状态
                payment = facadepayment;// 赋值给payment继续支付
            } else if (Constants.PAYMENT_STATUS_4.equals(status)) {
                return "/actirationCard/activatedCard/pay/serviceBusy";// 处理中状态直接返回服务器忙稍后重试
            }
        }

        // 支付前较验(生效日期10分钟内 不能支付)
        payService.validateBeforePay(tp);
        logger.info("暂存单号：" + decryptStagNo + "     流水号： "
                + payment.getTransNo());
        String transDate = DateUtil.format(payment.getTransDate(),
                "yyyy-MM-dd HH:mm:ss");
        String transDatestr = transDate.replaceAll("\\D", "");
        String checkStr = verificationCode + "comCode=" + payment.getComCode()
                + "&payID=" + payment.getPayId() + "&requestCode="
                + payment.getRequestCode() + "&transAmt="
                + payment.getTransAmt() + "&transDate=" + transDatestr
                + "&transNo=" + payment.getTransNo();
        logger.debug("支付checkStr:" + checkStr);
        String checkValue = MD5Util.md5One(checkStr).toLowerCase();
        model.put("payUrl", Config.getProp("nlife.pay.payUrl"));
        model.put("payment", payment);
        model.put("transDate", transDate);
        model.put("pageRetUrl", Config.getProp("nlife.callback.pageRetUrl"));
        model.put("bgRetUrl", Config.getProp("nlife.callback.bgRetUrl"));
        model.put("checkValue", checkValue);
        return "/actirationCard/activatedCard/pay/payment";
    }
    
    /**
     * 支付接口对接新支付平台 20190313 helina
     * 
     * @param stagNo
     *            暂存单号
     * @return
     */
    @RequestMapping(value = "/newpaymentmethod")
    public String newpaymentmethod(HttpSession session, ModelMap model,
            String stagNo, String type) throws AppException, Exception {
        // 解密
        String decryptStagNo = EncryptUtil.decrypt(stagNo);
        // 用户信息
        GatewayUser gatewayuser = (GatewayUser) session
                .getAttribute(Constants.SESSION_USER);

        FacadeTempPolicy tp = new FacadeTempPolicy();
        tp.setStagNo(decryptStagNo);
        tp = facadeTempPolicyService.findFacadeTempPolicy(tp);
        if (tp == null) {
            throw new AppException("暂存单号[" + decryptStagNo + "]无记录");
        }

        FacadeNewPayment facadeNewpayment = facadeNewPaymentDao
                .queryFacadeNewPaymentByPayidTheLatestInsertTime(decryptStagNo);
        FacadeNewPayment newpayment = new FacadeNewPayment();
        String status = "";
        if (facadeNewpayment == null) { // 无支付记录
        	newpayment = payService.noNewPaymentRecord(tp, gatewayuser.getUserCode());
        } else {
            status = facadeNewpayment.getTransState();//老的是status
            if (!Constants.NEW_PAYMENT_STATUS_2.equals(status)) {
            	newpayment = payService.noNewPaymentStatus(facadeNewpayment);// 支付表是未支付状态
                if (Constants.NEW_PAYMENT_STATUS_2.equals(newpayment.getTransState())) {// 如果查询到已经支付成功了则直接跳转到支付成功页面
                    List<FacadeAppForm> facadeappforms = payService
                            .alreadyPaymentStatus(decryptStagNo);

                    boolean flag = false;// 定义一个标志
                    for (FacadeAppForm facadeappform : facadeappforms) {// 循环判断是否有未生成的保单
                        if (StrUtil.isEmpty(facadeappform.getPolNo())) {
                            flag = true;
                            break;
                        }
                    }
                    if (flag) {// 如果有没生成的保单则调用缴费确认接口生成保单
                        payService.updateNewPayCostCallBack(facadeNewpayment);// 调用缴费确认
                    }
                    return "/actirationCard/activatedCard/pay/success";
                }
            } else if (Constants.NEW_PAYMENT_STATUS_2.equals(status)) {// 支付表是已支付状态
                List<FacadeAppForm> facadeappforms = payService
                        .alreadyPaymentStatus(decryptStagNo);

                boolean flag = false;// 定义一个标志
                for (FacadeAppForm facadeappform : facadeappforms) {// 循环判断是否有未生成的保单
                    if (StrUtil.isEmpty(facadeappform.getPolNo())) {
                        flag = true;
                        break;
                    }
                }
                if (flag) {// 如果有没生成的保单则调用缴费确认接口生成保单
                    payService.updateNewPayCostCallBack(facadeNewpayment);// 调用缴费确认
                }
                return "/actirationCard/activatedCard/pay/success";
                
            } 
        }

        Date date = new Date();
        String transDate = DateUtil.format(date, "yyyyMMddHHmmss");
        String transTime = DateUtil.format(date, "HHmmss");
        String transSeq = DateUtil.format(date, "yyyyMMddHHmmssSSS");
        String notifyURL = Config
                .getProp("card.pay.new.callback.notifyUrl");
        String returnURL = Config
                .getProp("card.pay.new.callback.returnUrl");
        String key = Config.getProp("card.newpay.key");
        String fixUser = "0";
        String sysCode = Config.getProp("card_code");
        Date expireDate = newpayment.getExpireDate();
        String expiredate = DateUtil.format(expireDate, "yyyyMMddHHmmss");
        String checkStr = "ApplyEntity=" + newpayment.getApplyEntity() + "&Cur="
                + "CNY" + "&Description=" + newpayment.getTitle() + "&ExpireDate="
                + expiredate + "&FixUser=" + fixUser + "&NotifyURL="
                + notifyURL + "&OurAmount=" + newpayment.getAmount()
                + "&PaymentCode=" + newpayment.getPaymentCode() + "&RdSeq="
                + newpayment.getRdSeq() + "&ReturnURL=" + returnURL
                + "&TransDate=" + transDate + "&TransSeq=" + transSeq
                + "&TransSource=" + sysCode + "&TransTime=" + transTime
                + "&Version=" + "1" + "&key=" + key;

        logger.debug("支付checkStr:" + checkStr);
        String S3Sign = MD5Util.md5One(checkStr);
        model.put("fixUser", fixUser);
        model.put("transSource", sysCode);
        model.put("expiredate", expiredate);
        model.put("payUrl", Config.getProp("card.newpay.payUrl"));
        model.put("newPayment", newpayment);
        model.put("transDate", transDate);
        model.put("transTime", transTime);
        model.put("transSeq", transSeq);
        model.put("S3Sign", S3Sign);
        model.put("notifyURL", notifyURL);
        model.put("returnURL", returnURL);
        
        return "/actirationCard/activatedCard/pay/newpayment";
    }
    
    

    /**
     * 支付回调接口 回调后调用缴费确认接口生成保单号
     * 
     * @param comCode
     *            机构代码
     * @param merId
     *            商户号
     * @param payAmt
     *            支付金额
     * @param payDate
     *            支付日期
     * @param payID
     *            支付单号
     * @param paymentType
     *            支付方式
     * @param payNo
     *            支付流水号
     * @param payResult
     *            支付结果
     * @param requestCode
     *            请求方代码
     * @param transDate
     *            交易时间
     * @param transNo
     *            交易流水号
     * @param checkValue
     *            加密串
     * @param payRemark
     *            支付结果描述
     * @param session
     */
    @RequestMapping(value = "/callBack")
    public String callBack(ModelMap model, String comCode, String merId,
            String payAmt, String payDate, String payID, String paymentType,
            String payNo, String payResult, String requestCode,
            String transDate, String transNo, String checkValue,
            String payRemark, HttpSession session) {
        // 获取合作验证码
        String verificationCode = GatewayCache
                .getCache(Constants.FACADE_PAYMENT_KEY);
        // 没有置空
        verificationCode = StrUtil.getValNoTrim(verificationCode);
        String payDateStr = payDate != null ? payDate.replaceAll("\\D", "")
                : null;
        String transDateStr = transDate != null ? transDate.replaceAll("\\D",
                "") : null;
        String checkStr = verificationCode + "comCode=" + comCode + "&merId="
                + merId + "&payAmt=" + payAmt + "&payDate=" + payDateStr
                + "&payID=" + payID + "&payNo=" + payNo + "&payResult="
                + payResult + "&paymentType=" + paymentType + "&requestCode="
                + requestCode + "&transDate=" + transDateStr + "&transNo="
                + transNo;

        try {
            // 检验参数是否正确
            if (checkValue.equals(MD5Util.md5One(checkStr).toLowerCase())) {
                logger.info("交易流水号:" + transNo + "校验成功");
                FacadePayment payment = new FacadePayment();
                payment.setTransNo(transNo);
                payment.setMerId(merId);
                payment.setPayNo(payNo);
                payment.setPayId(payID);
                payment.setPaymentType(paymentType);
                payment.setPayDate(DateUtil.parse(payDate,
                        "yyyy-MM-dd HH:mm:ss"));
                payment.setPayResult(payResult);
                payment.setPayRemark(payRemark);
                payment.setFeedbackDate(new Date());
                payment.setTransAmt(new BigDecimal(payAmt));
                if ("0000".equals(payResult)) {
                    payment.setStatus(Constants.PAYMENT_STATUS_2);
                } else {
                    payment.setStatus(Constants.PAYMENT_STATUS_3);
                }
                boolean backFalg = payService.updateFacade(payment);
                if (backFalg) {
                    // 当支付成功时候调用缴费功能
                    payService.updatePayCostCallBack(payment);
                }
                model.put("status", "success");
            } else {
                logger.info("交易流水号:" + transNo + "校验失败");
                model.put("status", "error");
            }
            logger.info("完成执行:/callBack");
            // 最终返回处理。。。
        } catch (Exception e1) {
            logger.error(e1);
            model.put("status", "error");
        }
        return "/actirationCard/activatedCard/pay/callBack";
    }
    
    /**
     * 集中收款平台回调   helina  20190318
     * 
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping(value = "/newCallBack")
    public void newCallBack(HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        logger.info("开始执行:/newCallBack");

        // 解析集中收款平台缴费信息回调报文
        StringBuilder jb = new StringBuilder();
        String line = null;
        BufferedReader reader = request.getReader();
        while ((line = reader.readLine()) != null) {
            jb.append(line);
        }
        Document xml = DocumentHelper.parseText(jb.toString());
        Element element = xml.getRootElement();
        String rdSeq = selectSingleNodeByRoot(element, "/ATS/IN/RD/RdSeq");
        String transState = selectSingleNodeByRoot(element,
                "/ATS/IN/RD/TransState");
        String cancelState = selectSingleNodeByRoot(element,
                "/ATS/IN/RD/CancelState");
        String Abstract = selectSingleNodeByRoot(element, "/ATS/IN/RD/Abstract");
        String recChannel = selectSingleNodeByRoot(element,
                "/ATS/IN/RD/RecChannel");
        String payMadeDate = selectSingleNodeByRoot(element,
                "/ATS/IN/RD/PayMadeDate");
        String corpAct = selectSingleNodeByRoot(element, "/ATS/IN/RD/CorpAct");

        Map<String, String> map = new HashMap<String, String>();
        long time1 = System.currentTimeMillis();
        HashMap<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("rdSeq", rdSeq);
        FacadeNewPayment facadepayment = payService
                .queryNewPayment(paramMap);// 查询支付表是否支付成功

        String status = facadepayment.getTransState();
        if (Constants.NEW_PAYMENT_STATUS_2.equals(status)) {
            // 已通知成功
            map.put("TransState", "2");
            map.put("RtnCode", "success");
        } else {
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sf.parse(payMadeDate);
            facadepayment.setRdSeq(rdSeq);
            facadepayment.setPayType(recChannel);
            facadepayment.setMerid(corpAct);
            facadepayment.setTransState(transState);
            facadepayment.setCancelState(cancelState);
            facadepayment.setPayDate(date);
            facadepayment.setFeedBackDate(new Date());
            facadepayment.setAbstracts(Abstract);
            boolean flag = false;
            boolean flagStatus = false;
            try {
                // 更新支付表状态
                flag =payService.updateFacadeNewPay(facadepayment);
                // TODO 收付款状态TransState:1-未收款 2-已收款 3-收款失败 4-收款中 5-收款未知
                // TODO 若返回1 4 5怎么处理?
                map.put("TransState", "2");
                map.put("RtnCode", "success");
            } catch (Exception e) {
                map.put("TransState", "3");
                map.put("ErrorMsg", "支付表更新失败");
                map.put("RtnCode", "exception");
            }
            if ("2".equals(transState) && flag) {
                try {
                	//更新暂存单表和投保单表状态 12 已支付
                	flagStatus = activatedService.afterPayUpdateStatus(facadepayment.getPayId());
                    if(flagStatus){
                    //进行缴费确认
                	payService.updateNewPayCostCallBack(facadepayment);
                	}
                } catch (Exception e) {
                    logger.error(e);
                }
            }
        }

        logger.info("请求[/newCallBack] 执行时间:"
                + (System.currentTimeMillis() - time1));
        logger.info("完成执行:/newCallBack");

        // 返回应答报文到集中收款平台
        String transSeq = selectSingleNodeByRoot(element, "/ATS/PUB/TransSeq");
        Date date = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("HHmmsss");
        map.put("TransDate", sdf1.format(date));
        map.put("TransTime", sdf2.format(date));
        map.put("TransSeq", transSeq);
        map.put("RdSeq", rdSeq);
        map.put("RtnMsg", "接收成功");
        String templates = Config.getProp("pay.NotifyRecState.templates");
        String process = FreeMarkerUtil.process(templates, map);
        logger.info("集中收款平台返回回调结果通知报文：" + process);
        response.setCharacterEncoding("utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(process);
        logger.info("完成执行:返回应答报文到集中收款平台");
        writer.flush();
        writer.close();
    }

    public String selectSingleNodeByRoot(Element root, String path) {
        Node node = root.selectSingleNode(path);
        if (node == null) {
            return "";
        } else {
            return node.getText();
        }
    }
    
    /**
     * helina  20190325
     * @param model
     * @param rdseq
     * @throws Exception
     */
    @RequestMapping(value = "/newCallBackCS")
    public String callBackCS() throws Exception {
    	logger.info("开始执行:/newCallBackCS");
        return "/actirationCard/activatedCard/pay/success";
    }
}
